package com.tinem.platform.module.starter.web.aop;

import com.tinem.platform.module.starter.web.annotation.MdcLog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author fengzhihao
 * @version v1
 * @program: platform
 * @className PageAop
 * @description TODO
 * @site 
 * @company 
 * @create 2020-07-14 22:03
 */
@Aspect
@Component
public class MdcLogAop {
    /**
     * 分页方法拦截
     * @param jp
     * @return
     * @throws Throwable
     */
    @Around("@annotation(com.tinem.platform.module.starter.web.annotation.MdcLog)")
    public Object log(ProceedingJoinPoint jp) throws Throwable {
        // 获取方法注解
        Signature signature = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        MdcLog mdcLog = method.getDeclaredAnnotation(MdcLog.class);

        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(mdcLog.value());

        //生成模版表达式
        Object[] values = jp.getArgs();
        String[] names = ((CodeSignature) jp.getSignature()).getParameterNames();

        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < names.length; i++) {
            context.setVariable(names[i], values[i]);
        }
        try {
            MDC.put(mdcLog.key(), (String) expression.getValue(context));
            return jp.proceed();
        }finally {
            MDC.remove(mdcLog.key());
        }
    }
}
